import path from "path";
import fs from "fs";
import * as cheerio from "cheerio";
import { ComponentInfo } from "../../common/src/ComponentInfo";
import { DistStruct } from "../../common/src/CreateDist";
import { LoadComponent } from "../../common/src/LoadComponent";
import { RunComponent } from "../../common/src/RunComponent";
import { Decode } from "./Decode";
import { ImplementComponent } from "./ImplementComponent";
import { componentNickname } from "./Main";
import { Resources } from "./Resources";
import { ComponentFolder } from "../../common/domain/ComponentFoder";
import { copyDir } from "../../common/src/utils/dir";

export class Assemble {
  private components: componentNickname[] = [];
  private projectRoot: string = "";
  private dist: DistStruct;
  private decoder: Decode;
  private indexFilePath: string | null = null;
  private $: cheerio.Root | null = null;
  private jsFileArr: string[] = [];
  private cssFileArr: string[] = [];
  private res: Resources;

  constructor(
    projectRoot: string,
    components: componentNickname[],
    dist: DistStruct,
    decoder: Decode,
    res: Resources
  ) {
    this.projectRoot = projectRoot;
    this.components = components;
    this.dist = dist;
    this.decoder = decoder;
    this.res = res;
    this.loadIndexFile();
  }

  public async load(cf: ComponentFolder) {
    for await (const component of this.components) {
      const ci = new ComponentInfo(component.componentName, this.projectRoot);
      const module = new LoadComponent(ci).loadComponent();

      const runtime = new RunComponent(
        ci,
        new module(),
        +component.componentId,
        this.dist
      );

      runtime.setRequiredRes(this.res.getResources());
      // const runtimeModule = runtime.getModule();
      // const resList = runtimeModule.require ? runtimeModule.require() : {};
      // for (const key in resList) {
      //   if (fs.existsSync(path.join(this.dist.getRootPath(), key))) {
      //     delete resList[key];
      //   }
      // }
      // runtime.handleResources(resList);

      if (!this.$) throw Error("cannot load html from file");
      const impl = new ImplementComponent(
        runtime,
        this.dist,
        this.decoder,
        this.$,
        this.cssFileArr,
        this.jsFileArr
      );

      impl.appendJs();
      // console.log("append css");
      await impl.appendCss();
    }
    // this.components.forEach((component) => {
    //   const ci = new ComponentInfo(component.componentName, this.projectRoot);
    //   const module = new LoadComponent(ci).loadComponent();
    //   const runtime = new RunComponent(
    //     ci,
    //     new module(),
    //     +component.componentId,
    //     this.dist
    //   );

    //   if (!this.$) throw Error("cannot load html from file");
    //   const impl = new ImplementComponent(
    //     runtime,
    //     this.dist,
    //     this.decoder,
    //     this.$,
    //     this.cssFileArr,
    //     this.jsFileArr
    //   );
    // });
    // this.useDefaultRes(cf);
    this.copyRes()
    this.quoteCss();
    this.quoteJs();
    this.saveChange();
  }

  private copyRes() {
    const from = path.join(this.projectRoot, 'dist/res/img')
    const to = path.join(this.projectRoot, 'result/res/img')

    copyDir(from, to)
  }

  private useDefaultRes(cf: ComponentFolder) {
    const files = fs.readdirSync(this.dist.getImgFolderPath());
    this.res.getResources().forEach((val) => {
      const exist = path.basename(val.after.val);
      if (files.indexOf(exist) !== -1) return;
      //copy img from components folder
      const componentName = val.after.name.split("_")[0];
      const from = path.join(cf.getPath(), componentName, val.before.val);
      const to = path.join(
        this.dist.getImgFolderPath(),
        path.basename(val.after.val)
      );

      // console.log(from, to);

      fs.copyFileSync(from, to);
    });
    // const required = this.res
    //   .getResources()
    //   .map((val) => path.basename(val.after.val));
    //copy dist/dist/res/img/...
    // path.basename()
  }

  private loadIndexFile() {
    this.indexFilePath = path.join(this.dist.getRootPath(), "index.html");
    const indexStr = fs.readFileSync(this.indexFilePath).toString();
    this.$ = cheerio.load(indexStr);
  }

  private getJsFileName() {
    return "integrateJs.js";
  }
  private getCssFileName() {
    return "integrateCss.css";
  }

  private quoteJs() {
    const absPath = path.join(
      this.dist.getJsFolderPath(),
      this.getJsFileName()
    );
    fs.writeFileSync(absPath, this.jsFileArr.join("\n"));
    const relative = path.relative(this.dist.getRootPath(), absPath);
    if (!this.$) throw Error("cannot load index file");
    this.$("body").append(`<script src="${relative}" ></script>`);
  }
  private quoteCss() {
    const absPath = path.join(
      this.dist.getCssFolderPath(),
      this.getCssFileName()
    );
    // console.log(this.cssFileArr.join("\n"));

    fs.writeFileSync(absPath, this.cssFileArr.join("\n"));
    const relative = path.relative(this.dist.getRootPath(), absPath);
    if (!this.$) throw Error("cannot load index file!");
    this.$("head").append(`<link href="${relative}" rel="stylesheet"/>`);
  }

  private saveChange() {
    if (!this.indexFilePath) throw Error("cannot find index file path");
    if (!this.$) throw Error("cannot load index file ");
    // console.log(this.$.html(), 'save');
    fs.writeFileSync(this.indexFilePath, this.$.html());
  }
}
